"""\
wrts.nl class models

R.R. Nederhoed (rr@nederhoed.com)
2007-06-24

TODO: unit tests for XML conversions instead of doctests

$Id: $
"""
__version__ = "$Revision: $"

# py 2.5+
from elementtree import ElementTree as ET

_WRTS_XML_MAP = {
    '_id': 'id',
    'lang_a': 'lang-a',
    'lang_b': 'lang-b',
}

_WRTS_XML_CONV = {
    'shared': lambda x:str(x).lower()
}

def wrtslist2xml(list_):
    """Convert WrtsList instance to wrts XML format 
    
    >>> list_ = WrtsList(id_=0)
    >>> wrtslist2xml(list_)
    '<list><id>0</id><shared>false</shared></list>'
    >>> list_.lang_a = 'EN'
    >>> list_.lang_b = 'NL'
    >>> wrtslist2xml(list_)
    '<list><id>0</id><lang-a>EN</lang-a><lang-b>NL</lang-b><shared>false</shared></list>'
    
    >>> list_ = WrtsList('Jaapaap')
    >>> wrtslist2xml(list_)
    '<list><title>Jaapaap</title><shared>false</shared></list>'
    
    >>> list_.keywords.append('banaan')
    >>> wrtslist2xml(list_)
    '<list><title>Jaapaap</title><shared>false</shared><keywords><keyword>banaan</keyword></keywords></list>'
    
    >>> list_.add_word_translation('baboon', 'baviaan')
    >>> wrtslist2xml(list_)
    '<list><title>Jaapaap</title><shared>false</shared><keywords><keyword>banaan</keyword></keywords><words><word><word-a>baboon</word-a><word-b>baviaan</word-b></word></words></list>'
    """
    root = ET.Element('list')
    # Basics
    for key in ('_id', 'title', 'lang_a', 'lang_b', 'shared'):
        tag = _WRTS_XML_MAP.get(key, key)
        # convert
        if list_.__dict__.get(key) is not None:
            tmp = ET.SubElement(root, tag)
            convert = _WRTS_XML_CONV.get(key, str)
            tmp.text = convert(list_.__dict__[key])
    # Keywords
    if list_.keywords:
        keywords = ET.SubElement(root, 'keywords')
        for value in list_.keywords:
            tmp = ET.SubElement(keywords, 'keyword')
            tmp.text = value
    # Translations
    if list_._translations:
        keywords = ET.SubElement(root, 'words')
        for (source, target) in list_._translations:
            tmp = ET.SubElement(keywords, 'word')
            ET.SubElement(tmp, 'word-a').text = source
            ET.SubElement(tmp, 'word-b').text = target
    
    return ET.tostring(root)

# MODEL
class WrtsList(object):
    """Basic functionality for a list of words
    
    Everything you can add using this class can be stored online using the API
    """
    def __init__(self, title=None, id_=None):
        """Constructor """
        self.title = title
        # unique id on wrts.nl
        self._id = id_
        # Extras
        self.lang_a = None
        self.lang_b = None
        self.shared = False  # default not shared
        #self.href = None
        # Data
        self.keywords = []
        # Translations
        self._translations = []
        # Indexing (todo)
        #self._words_ab = {}
        #self._words_ba = {}
    
    def __len__(self):
        """Size """
        return len(self._translations)
    
    def __str__(self):
        """String representation """
        result = """\
%s (id=%s)
keywords: %s
# words: %d
""" % (self.title, self._id, str(self.keywords), len(self))
        return result
    
    def add_word_translation(self, word_a, word_b):
        """Remember a translational combination """
        self._translations.append((word_a, word_b))
        # TODO: Indexing
        
    def get_word_translations(self, word, direction='ab'):
        """Return translations of the given word
        
        If you want to alter the direction of translation from
        language B to A, pass `direction`='ba'
        """
        if direction not in ('ab', 'ba'):
            raise ValueError("Expecting a translation direction: 'ab' or 'ba'")
        
        result = []
        for (source, target) in self._translations:
            if direction == 'ba':
                (target, source) = (source, target)
            if source == word:
                result.append(target)
        # TODO: raise not-in-list error?
        # Deliver
        return result

class ExamResult(object):
    """Representation of exam result
    
    Only cover the basics needed to generate charts
    
    This object is designed for read-only use.
    """
    def __init__(self, list_id):
        """Constructor """
        self.list_id = list_id
        # Optional
        self.score = None
        self.test_method = None
        self.seconds = None
        self.created = None
        # Direction of knowledge test
        self.test_order = None
    
    def __str__(self):
        """String representation """
        export = (self.list_id, self.created, self.score,
                  self.seconds, self.test_method, self.test_order)
        result = ', '.join([str(item) for item in export])
        return result
        
def main():
    """Program code """
    _test(True)

def _test(verbose=False):
    """Run tests on module """
    import doctest
    doctest.testmod(verbose=verbose)

if __name__ == "__main__":
    main()
